package com.ruoyi.network.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;


public class NPServer{
	private Selector selector;
	private ServerSocketChannel serverChannel;
	private String name;
	private int port;
	public ServerSocketChannel getServerChannel() {
		return serverChannel;
	}
	public Selector getSelector() {
		return selector;
	}
	public String getName() {
		return name;
	}
	public int getPort() {
		return port;
	}
	

	public NPServer(String name, int port, Selector selector) {
		try {
			this.name = name;
			this.port = port;
			this.selector = selector;
			// 打开监听通道
			serverChannel = ServerSocketChannel.open();
			// 如果为 true，则此通道将被置于阻塞模式；如果为 false，则此通道将被置于非阻塞模式
			serverChannel.configureBlocking(false);// 开启非阻塞模式			
			
			// 可选参数
			// 对所有连接都生效
			//禁用Nagle算法。Nagle算法是一种减少小包发送次数的技术，但它可能会导致延迟。通过设置TCP_NODELAY选项，你可以禁用Nagle算法，以减少数据传输的延迟。这可以通过调用
			//socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
			// 设置发送缓冲区大小
			//serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, Constant.SO_SNDBUF_SIZE);
			// 设置接收缓冲区大小(TCP协议滑动窗口)
			//虽然这不会直接影响对端的接收缓冲区，但增加客户端的发送缓冲区大小可以允许更多的数据在本地缓存，从而可能减少因网络拥塞导致的写操作阻塞
			//serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, Constant.SO_RCVBUF_SIZE);
			// 这个选项被启用时，它会在TCP连接空闲时自动发送探测包，以确保连接仍然有效。这通常用于检测"死"连接，即那些由于某种原因（如对方主机崩溃或网络中断）而不再可用的连接
			// 具体来说，当SO_KEEPALIVE选项被设置后，如果在一段时间内（通常是2小时，但这个值可能因操作系统而异）在TCP连接上没有数据交换，操作系统会自动发送一个"保持存活"（keepalive）探测包给对方。对方必须响应这个探测包。根据对方的响应，操作系统会采取适当的行动，如关闭连接或继续等待
			//serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
			// 当您调用close()方法时，底层TCP连接会尝试在1秒内发送和确认剩余的数据。如果在这段时间内所有数据都被成功处理，那么连接会正常关闭。否则，连接会被强制关闭
			//serverChannel.setOption(StandardSocketOptions.SO_LINGER, 5); // 设置linger时间为1秒 
			 
			
			
			// 绑定端口 backlog,最大通道连接数为1024
			serverChannel.socket().bind(new InetSocketAddress(port), 65535);
			
			// 监听客户端连接请求;
			// 一个selector可以关联多个channel
			// selector可以轮询各个channel,当有读写事件时执行业务逻辑
			serverChannel.register(selector, SelectionKey.OP_ACCEPT);
			System.out.println(this.name  + "已启动，端口：" + port);
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		}
	}
}
